#include "cuda_controller.h"
#include <cuda_gl_interop.h>
#include "common/vconsole.h"
#include "common/defs.h"
#include <vector_types.h>
#include <vector_functions.h>
//#include <cutil_math.h>    
#include <cuda_runtime_api.h>
#include "cuda_files/objects.cuh"

extern "C" void trace(uchar4 *out_data, const float3 camera_position, const float3 ligth_position, const float3 light_color);

cuda_controller::cuda_controller()
    : __pixel_buffer(0),
      __result_texture(0)
{

}

cuda_controller::~cuda_controller()
{

}

bool cuda_controller::init()
{/*
    float *a = new float[2];
    a[0] = 144;
    a[1] = 255;
    if (cudaSuccess != cudaMemcpyToSymbol(cmem, a, sizeof(float) * 2, 0, cudaMemcpyHostToDevice))
    {
        vconsole::print_status("error", CUDA_CONTROLLER, false);
        return false;
    }*/
    /*
    float4 tmp = make_float4(155, 255, 0, 0);
    if (cudaSuccess != cudaMemcpyToSymbol(&cmem, &tmp, sizeof(float4), 0, cudaMemcpyHostToDevice))
    {
        vconsole::print_status("error", CUDA_CONTROLLER, false);
        cudaError_t err = cudaGetLastError();
        if( cudaSuccess != err)
        {
            fprintf(stderr, "Cuda error: %s.\n", cudaGetErrorString( err) );
        }
        return false;
    }*/

    
    
    if (cudaSuccess == cudaGLSetGLDevice(0))
    {
    vconsole::print_status("cuda init", CUDA_CONTROLLER, true);    
        return true;
    }
    
    vconsole::print_status("cuda init", CUDA_CONTROLLER, false);
    return false;
}

bool cuda_controller::register_buffer()
{
    cudaGLRegisterBufferObject(__pixel_buffer);
    return true;
}

bool cuda_controller::recalculate()
{
    /*
    base_abstract_object<float3> *base = new sphere<float3, float>(make_float3(300, 400, 50), 50);
    base_abstract_object<float3> *dev_ptr;
    
    cudaMalloc((void**)&dev_ptr, sizeof(sphere<float3, float>));
    cudaMemcpy(dev_ptr, base, sizeof(sphere<float3, float>), cudaMemcpyHostToDevice);
    */
    
    uchar4 *dptr = 0;

    // map OpenGL buffer object for writing from CUDA on a single GPU
    // no data is moved (Win & Linux). When mapped to CUDA, OpenGL
    // should not use this buffer
    cudaGLMapBufferObject((void**)&dptr, __pixel_buffer);

    static float x = -1000;
    // execute the kernel
    trace(dptr, make_float3(300, 300, -1000), make_float3(x, 400, 500), make_float3(255, 0, 0));
    
    x += 5;
    // unmap buffer object
    cudaGLUnmapBufferObject(__pixel_buffer);
    
    return true;
}
